using System;

namespace ValidationFramework.Configuration.Reflection
{
    /// <summary>
    /// Base class for all <see cref="Attribute"/>s that define <see cref="Rule"/>s.
    /// </summary>
    /// <seealso cref="IRuleAttribute"/>
    /// <example>
    /// <b>Extending the validation framework</b><br/>
    /// <code source="Examples\ExampleLibraryCSharp\NewRule\RequiredCharacterRule.cs" title="Implementing a custom rule by inheriting from Rule" lang="cs"/>
    /// <code source="Examples\ExampleLibraryVB\NewRule\RequiredCharacterRule.vb" title="Implementing a custom rule by inheriting from Rule" lang="vbnet"/>
    /// <code source="Examples\ExampleLibraryCSharp\NewRule\RequiredCharacterRuleAttribute.cs" title="Creating a IRuleAttribute for that Rule" lang="cs"/>
    /// <code source="Examples\ExampleLibraryVB\NewRule\RequiredCharacterRuleAttribute.vb" title="Creating a IRuleAttribute for that Rule" lang="vbnet"/>
    /// <code source="Examples\ExampleLibraryCSharp\NewRule\RequiredCharacterRuleConfigReader.cs" title="Creating IRuleConfigReader for that Rule." lang="cs"/>
    /// <code source="Examples\ExampleLibraryCSharp\NewRule\RequiredCharacterRuleConfigReaderUsage.cs" title="Using the custom ConfigReader." lang="cs"/>
    /// <code source="Examples\ExampleLibraryVB\NewRule\RequiredCharacterRuleConfigReader.vb" title="Creating IRuleConfigReader for that Rule." lang="vbnet"/>
    /// <code source="Examples\ExampleLibraryVB\NewRule\RequiredCharacterRuleConfigReaderUsage.vb" title="Using the custom ConfigReader." lang="vbnet"/>
    /// <code source="Examples\ExampleLibraryCSharp\NewRule\ClientRegularExpressionWebValidator.cs" title="A custom RegularExpressionValidator that only validates on the client side." lang="cs"/>
    /// <code source="Examples\ExampleLibraryVB\NewRule\ClientRegularExpressionWebValidator.vb" title="A custom RegularExpressionValidator that only validates on the client side." lang="vbnet"/>
	/// </example>
#if (!SILVERLIGHT)
    [Serializable]
#endif
	[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
    public abstract class RuleAttribute : Attribute, IRuleAttribute
    {
		// --- Constructors 		
		
		/// <summary>
		/// Initializes a new instance of the RuleAttribute class.
		/// </summary>
		public RuleAttribute()
		{		
			Scope = RuleScope.Member;
			UseErrorMessageProvider = false;
			ErrorMessage = string.Empty;
			RuleSet = string.Empty;
		}


		// --- Properties

        /// <seealso cref="Rule.UseErrorMessageProvider"/>
        public bool UseErrorMessageProvider
        {
            get;
            set;
        }

		// --- Methods

		/// <summary>
		/// Creates a validator for use when validating a rule
		/// </summary>
		/// <param name="descriptor">The cached member type this rule is being applied to.</param>
		/// <returns></returns>
		public abstract ISpecification CreateSpecification(ICachedReflectionInfo descriptor);


        // --- IRuleAttribute | Members

        /// <summary>
        /// Gets or sets A <see cref="string"/> used to group <see cref="Rule"/>s. Use a null to indicate no grouping.
        /// </summary>
        public string RuleSet
        {
            get;
            set;
        }

		/// <inheritdoc />
        public string ErrorMessage
        {
            get;
            set;
        }

		/// <summary>
		/// The scope of this rule.
		/// </summary>
		public RuleScope Scope
		{
			get;
			set;
		}

		
		// --- IRuleAttibute | Methods

		/// <inheritdoc />
		public Rule CreateRule(ICachedReflectionInfo descriptor)
		{
			var rule = new Rule(CreateSpecification(descriptor));
			rule.ErrorMessage = ErrorMessage;
			rule.RuleSet = RuleSet;
			rule.UseErrorMessageProvider = UseErrorMessageProvider;

			return rule;
		}
    }
}